-- Lua Battle System - AI参数动态调优器
-- 提供智能的AI参数自动调优和自适应优化功能

local Logger = require("utils.logger")
local TableUtils = require("utils.table_utils")
local AIQualityAssessor = require("ai.ai_quality_assessor")

local AIParameterTuner = {
    -- 调优器配置
    config = {
        -- 调优间隔
        tuning_interval = 10, -- 每10次决策后进行一次调优评估

        -- 学习率
        learning_rate = 0.1, -- 参数调整的学习率

        -- 调优阈值
        tuning_threshold = 0.15, -- 性能下降超过15%时触发调优

        -- 历史数据保留
        history_size = 100, -- 保留最近100次决策的历史数据

        -- 参数调整范围
        adjustment_bounds = {
            min = 0.1, -- 参数最小值
            max = 1.0  -- 参数最大值
        },

        -- 调优策略
        strategies = {
            "gradient_descent", -- 梯度下降
            "bayesian_optimization", -- 贝叶斯优化
            "reinforcement_learning", -- 强化学习
            "genetic_algorithm" -- 遗传算法
        }
    },

    -- 当前状态
    state = {
        is_tuning_enabled = false,
        current_strategy = "gradient_descent",
        tuning_cycle = 0,
        last_tuning_time = 0,
        performance_history = {},
        parameter_history = {},
        optimization_progress = 0
    },

    -- 参数模板
    parameter_templates = {
        tactical_ai = {
            tactic_weights = {
                damage_output = { current = 0.3, min = 0.1, max = 0.5, step = 0.05 },
                team_survival = { current = 0.3, min = 0.1, max = 0.5, step = 0.05 },
                resource_efficiency = { current = 0.2, min = 0.05, max = 0.3, step = 0.05 },
                status_effects = { current = 0.2, min = 0.05, max = 0.3, step = 0.05 }
            },
            aggression = { current = 0.7, min = 0.3, max = 1.0, step = 0.1 },
            caution = { current = 0.5, min = 0.2, max = 0.8, step = 0.1 },
            adaptability = { current = 0.8, min = 0.5, max = 1.0, step = 0.1 }
        },
        decision_maker = {
            exploration_rate = { current = 0.1, min = 0.05, max = 0.3, step = 0.05 },
            exploitation_rate = { current = 0.9, min = 0.7, max = 0.95, step = 0.05 },
            memory_decay = { current = 0.95, min = 0.9, max = 0.99, step = 0.01 },
            innovation_factor = { current = 0.2, min = 0.1, max = 0.4, step = 0.05 }
        }
    },

    -- 性能指标
    performance_metrics = {
        decision_quality = { weight = 0.4, trend = "stable" },
        response_time = { weight = 0.2, trend = "stable" },
        success_rate = { weight = 0.3, trend = "stable" },
        adaptability_score = { weight = 0.1, trend = "stable" }
    }
}

-- 初始化调优器
function AIParameterTuner:init(ai_instance, config)
    ai_instance = ai_instance or self -- 如果没有提供实例，使用自己
    config = config or {}
    self.state.assessor = AIQualityAssessor:new()

    -- 合并配置
    if config then
        TableUtils.merge(self.config, config)
    end

    -- 初始化参数副本
    self.state.current_parameters = TableUtils.deep_copy(self.parameter_templates)

    -- 启用调优
    self.state.is_tuning_enabled = true
    self.state.last_tuning_time = os.time()

    Logger.info("AI参数调优器初始化完成")
end

-- 记录决策和性能数据
function AIParameterTuner:record_decision(decision_context, performance_data)
    if not self.state.is_tuning_enabled then
        return
    end

    local record = {
        timestamp = os.time(),
        decision_context = decision_context,
        performance = performance_data,
        parameters = TableUtils.deep_copy(self.state.current_parameters),
        battle_state = self:extract_battle_state(decision_context)
    }

    -- 添加到历史记录
    table.insert(self.state.performance_history, record)

    -- 限制历史记录大小
    if #self.state.performance_history > self.config.history_size then
        table.remove(self.state.performance_history, 1)
    end

    -- 检查是否需要调优
    self:check_tuning_needed()
end

-- 提取战斗状态特征
function AIParameterTuner:extract_battle_state(decision_context)
    local battle_state = {
        turn_count = decision_context.turn_count or 0,
        player_health_ratio = self:calculate_health_ratio(decision_context.allies),
        enemy_health_ratio = self:calculate_health_ratio(decision_context.enemies),
        resource_advantage = self:calculate_resource_advantage(decision_context),
        positional_advantage = self:calculate_positional_advantage(decision_context),
        status_effect_balance = self:calculate_status_balance(decision_context)
    }

    return battle_state
end

-- 计算生命值比率
function AIParameterTuner:calculate_health_ratio(characters)
    if not characters or #characters == 0 then
        return 0
    end

    local total_health = 0
    local max_health = 0

    for _, char in ipairs(characters) do
        if char.is_alive then
            total_health = total_health + char.hp
            max_health = max_health + char.max_hp
        end
    end

    return max_health > 0 and (total_health / max_health) or 0
end

-- 计算资源优势
function AIParameterTuner:calculate_resource_advantage(decision_context)
    local player_resources = 0
    local enemy_resources = 0

    -- 计算玩家方资源
    if decision_context.allies then
        for _, char in ipairs(decision_context.allies) do
            if char.is_alive then
                player_resources = player_resources + char.mp + #char.items * 10
            end
        end
    end

    -- 计算敌方资源
    if decision_context.enemies then
        for _, char in ipairs(decision_context.enemies) do
            if char.is_alive then
                enemy_resources = enemy_resources + char.mp + #char.items * 10
            end
        end
    end

    local total = player_resources + enemy_resources
    return total > 0 and ((player_resources - enemy_resources) / total) or 0
end

-- 计算位置优势
function AIParameterTuner:calculate_positional_advantage(decision_context)
    -- 简化的位置优势计算
    -- 实际游戏中可以根据地形、距离等因素计算
    return (math.random(-20, 20) / 100.0) -- 临时随机值
end

-- 计算状态效果平衡
function AIParameterTuner:calculate_status_balance(decision_context)
    local positive_effects = 0
    local negative_effects = 0

    -- 计算玩家方和敌方的状态效果
    local characters = {}
    if decision_context.allies then
        for _, char in ipairs(decision_context.allies) do
            table.insert(characters, {side = "player", status = char.status_effects or {}})
        end
    end

    if decision_context.enemies then
        for _, char in ipairs(decision_context.enemies) do
            table.insert(characters, {side = "enemy", status = char.status_effects or {}})
        end
    end

    for _, char in ipairs(characters) do
        for effect_name, _ in pairs(char.status) do
            if char.side == "player" then
                if string.find(effect_name, "buff") then
                    positive_effects = positive_effects + 1
                elseif string.find(effect_name, "debuff") then
                    negative_effects = negative_effects + 1
                end
            else
                if string.find(effect_name, "buff") then
                    negative_effects = negative_effects + 1
                elseif string.find(effect_name, "debuff") then
                    positive_effects = positive_effects + 1
                end
            end
        end
    end

    local total = positive_effects + negative_effects
    return total > 0 and ((positive_effects - negative_effects) / total) or 0
end

-- 检查是否需要调优
function AIParameterTuner:check_tuning_needed()
    if #self.state.performance_history < self.config.tuning_interval then
        return false
    end

    -- 计算最近性能趋势
    local recent_performance = self:calculate_recent_performance()
    local baseline_performance = self:calculate_baseline_performance()

    -- 检查性能下降是否超过阈值
    local performance_drop = baseline_performance - recent_performance
    local needs_tuning = performance_drop > self.config.tuning_threshold

    if needs_tuning then
        Logger.info("检测到性能下降，触发参数调优", {
            drop = string.format("%.2f%%", performance_drop * 100),
            recent = string.format("%.2f", recent_performance),
            baseline = string.format("%.2f", baseline_performance)
        })

        self:perform_tuning()
    end

    return needs_tuning
end

-- 计算最近的性能指标
function AIParameterTuner:calculate_recent_performance()
    local recent_count = math.min(10, #self.state.performance_history)
    local start_idx = #self.state.performance_history - recent_count + 1

    local total_score = 0
    local total_weight = 0

    for i = start_idx, #self.state.performance_history do
        local record = self.state.performance_history[i]

        -- 计算综合性能分数
        local decision_score = record.performance.decision_score or 0
        local response_time = record.performance.response_time or 0
        local success = record.performance.success or false

        -- 综合评分（考虑多个指标）
        local combined_score = (
            decision_score * self.performance_metrics.decision_quality.weight +
            (1 - math.min(response_time / 100, 1)) * self.performance_metrics.response_time.weight +
            (success and 1 or 0) * self.performance_metrics.success_rate.weight
        )

        total_score = total_score + combined_score
        total_weight = total_weight + 1
    end

    return total_weight > 0 and (total_score / total_weight) or 0
end

-- 计算基准性能
function AIParameterTuner:calculate_baseline_performance()
    local baseline_count = math.min(50, #self.state.performance_history)

    if baseline_count < 10 then
        return 0.5 -- 默认基准性能
    end

    local total_score = 0
    local total_weight = 0

    -- 使用前50%的数据作为基准
    for i = 1, baseline_count do
        local record = self.state.performance_history[i]

        local decision_score = record.performance.decision_score or 0
        local response_time = record.performance.response_time or 0
        local success = record.performance.success or false

        local combined_score = (
            decision_score * self.performance_metrics.decision_quality.weight +
            (1 - math.min(response_time / 100, 1)) * self.performance_metrics.response_time.weight +
            (success and 1 or 0) * self.performance_metrics.success_rate.weight
        )

        total_score = total_score + combined_score
        total_weight = total_weight + 1
    end

    return total_weight > 0 and (total_score / total_weight) or 0.5
end

-- 执行参数调优
function AIParameterTuner:perform_tuning()
    Logger.info("开始AI参数调优", {
        strategy = self.state.current_strategy,
        cycle = self.state.tuning_cycle
    })

    self.state.tuning_cycle = self.state.tuning_cycle + 1

    -- 根据选择的策略进行调优
    local strategy_func = self["tune_with_" .. self.state.current_strategy]
    if strategy_func then
        strategy_func(self)
    else
        Logger.warn("未知的调优策略: " .. self.state.current_strategy)
        self:tune_with_gradient_descent()
    end

    -- 应用新参数
    self:apply_tuned_parameters()

    -- 记录参数历史
    self:record_parameter_history()

    Logger.info("AI参数调优完成", {
        cycle = self.state.tuning_cycle,
        optimization_progress = string.format("%.1f%%", self.state.optimization_progress * 100)
    })
end

-- 梯度下降调优策略
function AIParameterTuner:tune_with_gradient_descent()
    local gradient = self:calculate_parameter_gradient()

    -- 更新参数
    for category, params in pairs(self.state.current_parameters) do
        for param_name, param_info in pairs(params) do
            if gradient[category] and gradient[category][param_name] then
                local gradient_value = gradient[category][param_name]
                local adjustment = gradient_value * self.config.learning_rate

                -- 安全检查：确保参数结构完整
                if not param_info.current or not param_info.min or not param_info.max then
                    Logger.warn("参数结构不完整，跳过调整", {
                        category = category,
                        parameter = param_name,
                        has_current = param_info.current ~= nil,
                        has_min = param_info.min ~= nil,
                        has_max = param_info.max ~= nil
                    })
                    goto continue_parameter
                end

                -- 应用调整
                local new_value = param_info.current + adjustment

                -- 限制在边界范围内
                new_value = math.max(param_info.min, math.min(param_info.max, new_value))

                param_info.current = new_value

                Logger.debug("参数调整", {
                    category = category,
                    parameter = param_name,
                    old_value = string.format("%.3f", param_info.current - adjustment),
                    new_value = string.format("%.3f", new_value),
                    gradient = string.format("%.3f", gradient_value)
                })
            end
            ::continue_parameter::
        end
    end
end

-- 计算参数梯度
function AIParameterTuner:calculate_parameter_gradient()
    local gradient = {}

    -- 分析最近决策的特征
    local recent_decisions = self:get_recent_decisions(20)
    if #recent_decisions < 5 then
        return {}
    end

    -- 为每个参数计算梯度
    for category, params in pairs(self.state.current_parameters) do
        gradient[category] = {}

        for param_name, param_info in pairs(params) do
            local correlation = self:calculate_parameter_correlation(
                recent_decisions, category, param_name
            )

            gradient[category][param_name] = correlation
        end
    end

    return gradient
end

-- 计算参数与性能的关联性
function AIParameterTuner:calculate_parameter_correlation(decisions, category, param_name)
    local values = {}
    local performances = {}

    for _, decision in ipairs(decisions) do
        local param_value = decision.parameters[category][param_name].current
        local performance = decision.performance.decision_score or 0

        table.insert(values, param_value)
        table.insert(performances, performance)
    end

    return self:calculate_correlation(values, performances)
end

-- 计算两个序列的相关性
function AIParameterTuner:calculate_correlation(x_values, y_values)
    if #x_values ~= #y_values or #x_values < 2 then
        return 0
    end

    -- 计算均值
    local x_mean = 0
    local y_mean = 0

    for i = 1, #x_values do
        x_mean = x_mean + x_values[i]
        y_mean = y_mean + y_values[i]
    end

    x_mean = x_mean / #x_values
    y_mean = y_mean / #y_values

    -- 计算协方差和方差
    local covariance = 0
    local x_variance = 0
    local y_variance = 0

    for i = 1, #x_values do
        local x_diff = x_values[i] - x_mean
        local y_diff = y_values[i] - y_mean

        covariance = covariance + x_diff * y_diff
        x_variance = x_variance + x_diff * x_diff
        y_variance = y_variance + y_diff * y_diff
    end

    -- 计算相关系数
    if x_variance == 0 or y_variance == 0 then
        return 0
    end

    local correlation = covariance / math.sqrt(x_variance * y_variance)
    return math.max(-1, math.min(1, correlation))
end

-- 获取最近的决策记录
function AIParameterTuner:get_recent_decisions(count)
    local recent = {}
    local start_idx = math.max(1, #self.state.performance_history - count + 1)

    for i = start_idx, #self.state.performance_history do
        table.insert(recent, self.state.performance_history[i])
    end

    return recent
end

-- 应用调优后的参数
function AIParameterTuner:apply_tuned_parameters()
    if not self.state.ai_instance then
        return
    end

    -- 应用战术AI参数
    if self.state.ai_instance.tactics then
        local tactical_params = self.state.current_parameters.tactical_ai

        -- 更新权重
        if self.state.ai_instance.tactic_weights then
            for weight_name, weight_info in pairs(tactical_params.tactic_weights) do
                if self.state.ai_instance.tactic_weights[weight_name] then
                    self.state.ai_instance.tactic_weights[weight_name] = weight_info.current
                end
            end
        end

        -- 更新其他参数
        self.state.ai_instance.aggression = tactical_params.aggression.current
        self.state.ai_instance.caution = tactical_params.caution.current
        self.state.ai_instance.adaptability = tactical_params.adaptability.current
    end

    Logger.info("已应用调优后的AI参数")
end

-- 记录参数历史
function AIParameterTuner:record_parameter_history()
    local record = {
        timestamp = os.time(),
        cycle = self.state.tuning_cycle,
        parameters = TableUtils.deep_copy(self.state.current_parameters),
        strategy = self.state.current_strategy,
        performance = self:calculate_recent_performance()
    }

    table.insert(self.state.parameter_history, record)

    -- 限制历史记录大小
    if #self.state.parameter_history > 50 then
        table.remove(self.state.parameter_history, 1)
    end
end

-- 获取调优报告
function AIParameterTuner:get_tuning_report()
    local report = {
        summary = {
            is_enabled = self.state.is_tuning_enabled,
            current_strategy = self.state.current_strategy,
            tuning_cycles = self.state.tuning_cycle,
            optimization_progress = self.state.optimization_progress,
            last_tuning = self.state.last_tuning_time
        },

        current_parameters = self.state.current_parameters,

        performance_trend = self:analyze_performance_trend(),

        parameter_efficiency = self:analyze_parameter_efficiency(),

        recommendations = self:generate_tuning_recommendations()
    }

    return report
end

-- 分析性能趋势
function AIParameterTuner:analyze_performance_trend()
    if #self.state.performance_history < 10 then
        return {trend = "insufficient_data", confidence = 0}
    end

    local performances = {}
    for i = math.max(1, #self.state.performance_history - 9), #self.state.performance_history do
        local record = self.state.performance_history[i]
        local perf = record.performance.decision_score or 0
        table.insert(performances, perf)
    end

    -- 计算趋势
    local trend = self:calculate_linear_trend(performances)

    return {
        trend = trend > 0.1 and "improving" or trend < -0.1 and "declining" or "stable",
        slope = trend,
        confidence = math.min(1, #performances / 20)
    }
end

-- 计算线性趋势
function AIParameterTuner:calculate_linear_trend(values)
    if #values < 2 then
        return 0
    end

    local n = #values
    local sum_x = 0
    local sum_y = 0
    local sum_xy = 0
    local sum_x2 = 0

    for i, y in ipairs(values) do
        sum_x = sum_x + i
        sum_y = sum_y + y
        sum_xy = sum_xy + i * y
        sum_x2 = sum_x2 + i * i
    end

    local slope = (n * sum_xy - sum_x * sum_y) / (n * sum_x2 - sum_x * sum_x)
    return slope
end

-- 分析参数效率
function AIParameterTuner:analyze_parameter_efficiency()
    local efficiency = {}

    for category, params in pairs(self.state.current_parameters) do
        efficiency[category] = {}

        for param_name, param_info in pairs(params) do
            local correlation = self:calculate_parameter_impact(category, param_name)

            efficiency[category][param_name] = {
                current_value = param_info.current,
                utilization_rate = math.abs(correlation),
                impact_score = correlation,
                efficiency = math.abs(correlation) > 0.1 and "high" or
                             math.abs(correlation) > 0.05 and "medium" or "low"
            }
        end
    end

    return efficiency
end

-- 计算参数影响
function AIParameterTuner:calculate_parameter_impact(category, param_name)
    if #self.state.performance_history < 10 then
        return 0
    end

    local decisions = self:get_recent_decisions(20)
    return self:calculate_parameter_correlation(decisions, category, param_name)
end

-- 生成调优建议
function AIParameterTuner:generate_tuning_recommendations()
    local recommendations = {}

    -- 性能分析建议
    local performance_trend = self:analyze_performance_trend()
    if performance_trend.trend == "declining" then
        table.insert(recommendations, {
            type = "performance",
            priority = "high",
            message = "性能呈下降趋势，建议增加调优频率或调整学习率",
            action = "increase_tuning_frequency"
        })
    end

    -- 参数效率建议
    local efficiency = self:analyze_parameter_efficiency()
    for category, params in pairs(efficiency) do
        for param_name, info in pairs(params) do
            if info.efficiency == "low" then
                table.insert(recommendations, {
                    type = "parameter",
                    priority = "medium",
                    message = string.format("参数 %s.%s 效率较低，建议调整权重或范围", category, param_name),
                    action = "adjust_parameter_range",
                    target = {category = category, parameter = param_name}
                })
            end
        end
    end

    -- 策略建议
    if self.state.tuning_cycle > 10 and performance_trend.trend == "stable" then
        table.insert(recommendations, {
            type = "strategy",
            priority = "low",
            message = "当前策略效果稳定，可尝试更高级的优化策略",
            action = "upgrade_strategy"
        })
    end

    return recommendations
end

-- 切换调优策略
function AIParameterTuner:switch_strategy(new_strategy)
    if not new_strategy or new_strategy == self.state.current_strategy then
        return false
    end

    -- 验证策略是否支持
    local supported = false
    for _, strategy in ipairs(self.config.strategies) do
        if strategy == new_strategy then
            supported = true
            break
        end
    end

    if not supported then
        Logger.warn("不支持的调优策略: " .. new_strategy)
        return false
    end

    local old_strategy = self.state.current_strategy
    self.state.current_strategy = new_strategy

    Logger.info("切换调优策略", {
        from = old_strategy,
        to = new_strategy
    })

    return true
end

-- 手动触发调优
function AIParameterTuner:force_tuning()
    if not self.state.is_tuning_enabled then
        Logger.warn("调优器未启用")
        return false
    end

    Logger.info("手动触发参数调优")
    self:perform_tuning()
    return true
end

-- 启用/禁用调优器
function AIParameterTuner:set_enabled(enabled)
    self.state.is_tuning_enabled = enabled

    Logger.info("调优器" .. (enabled and "已启用" or "已禁用"))

    if enabled then
        self.state.last_tuning_time = os.time()
    end
end

-- 重置调优器
function AIParameterTuner:reset()
    Logger.info("重置AI参数调优器")

    -- 重置状态
    self.state.tuning_cycle = 0
    self.state.optimization_progress = 0
    self.state.performance_history = {}
    self.state.parameter_history = {}

    -- 重置参数到默认值
    self.state.current_parameters = TableUtils.deep_copy(self.parameter_templates)

    -- 应用默认参数
    self:apply_tuned_parameters()
end

-- 调优器状态检查
function AIParameterTuner:health_check()
    local health = {
        status = "healthy",
        issues = {},
        metrics = {}
    }

    -- 检查历史数据
    if #self.state.performance_history < 5 then
        table.insert(health.issues, "性能历史数据不足")
        health.status = "warning"
    end

    -- 检查参数范围
    for category, params in pairs(self.state.current_parameters) do
        for param_name, param_info in pairs(params) do
            if param_info.current < param_info.min or param_info.current > param_info.max then
                table.insert(health.issues,
                    string.format("参数 %s.%s 超出有效范围", category, param_name))
                health.status = "error"
            end
        end
    end

    -- 收集指标
    health.metrics = {
        tuning_cycles = self.state.tuning_cycle,
        data_points = #self.state.performance_history,
        optimization_progress = self.state.optimization_progress,
        last_tuning_delta = os.time() - self.state.last_tuning_time
    }

    return health
end

-- 导出调优数据
function AIParameterTuner:export_data()
    return {
        config = self.config,
        state = self.state,
        parameter_templates = self.parameter_templates,
        performance_metrics = self.performance_metrics,
        export_timestamp = os.time()
    }
end

-- 导入调优数据
function AIParameterTuner:import_data(data)
    if not data or not data.state then
        Logger.error("无效的调优数据")
        return false
    end

    -- 备份当前状态
    local backup = TableUtils.deep_copy(self.state)

    -- 导入数据
    self.state = data.state

    -- 验证数据完整性
    local health = self:health_check()
    if health.status == "error" then
        Logger.warn("导入的调优数据存在问题，恢复备份")
        self.state = backup
        return false
    end

    Logger.info("成功导入调优数据")
    return true
end

-- 创建调优器实例
function AIParameterTuner:new(config)
    local instance = {
        config = TableUtils.deep_copy(self.config),
        state = TableUtils.deep_copy(self.state),
        parameter_templates = TableUtils.deep_copy(self.parameter_templates),
        performance_metrics = TableUtils.deep_copy(self.performance_metrics)
    }

    setmetatable(instance, {__index = self})

    if config then
        TableUtils.merge(instance.config, config)
    end

    -- 初始化调优器
    instance:init(nil, config)

    return instance
end

return AIParameterTuner